-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make sure the first result in most recents is highlighted when user uses CMD+K #52298
Conversation
@Pujan92 should we implement this on mobile native and mweb? or only on large screen(desktop and desktop web)? Since the enter key hint displayed in the small screen width is "search". And on native mobile clicking search/enter key will always navigate to search page although the search input is empty, instead of navigating to the focused report 2024-11-11.at.10.40.47.mp4 |
Reviewer Checklist
Screenshots/VideosAndroid: mWeb ChromeiOS: mWeb SafariMacOS: Chrome / SafariScreen.Recording.2024-11-27.at.18.27.43.movMacOS: DesktopScreen.Recording.2024-11-27.at.18.36.32.mov |
useEffect(() => { | ||
if ((!isWeb && !isDesktop) || textInputValue) { | ||
return; | ||
} | ||
setInitialFocus(); | ||
}, [setInitialFocus, textInputValue, isWeb, isDesktop]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useEffect(() => { | |
if ((!isWeb && !isDesktop) || textInputValue) { | |
return; | |
} | |
setInitialFocus(); | |
}, [setInitialFocus, textInputValue, isWeb, isDesktop]); | |
useEffect(() => { | |
if ((!isWeb && !isDesktop)) { | |
return; | |
} | |
setInitialFocus(); | |
}, [setInitialFocus, isWeb, isDesktop]); |
Let search change focus be handled by onSearchChange function instead of making call to setInitialFocus
twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah you are right, it calls the setInitialFocus
twice
But this is intentional actually, if we dont early return when the textInputValue
is not empty, it will trigger the setInitialFocus();
since setInitialFocus
updated due to contextualReportData
updated when we input search term
See this video
New-Expensify.35.mp4
I think we should remove setInitialFocus();
on onSearchChange
instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As of now we need to focus only for the first time we can remove this entire function and use initiallyFocusedOptionKey
as mentioned here. We won't consider of refocusing when the input is cleared by user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we use initiallyFocusedOptionKey
, it will still focus on all platforms. Don’t we not need to focus on the mobile platform?
New-Expensify.mp4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For that, we can use isLargeScreenWidth and set undefined initiallyFocusedOptionKey based on it.
const focusedItem = flattenedSections.allOptions.at(index); | ||
if (focusedItem) { | ||
onArrowFocus(focusedItem); | ||
} | ||
(shouldDebounceScrolling ? debouncedScrollToIndex : scrollToIndex)(index, true); | ||
if (shouldScrollToIndex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (shouldScrollToIndex) { | |
if (shouldScrollToFocusedIndex) { | |
(shouldDebounceScrolling ? debouncedScrollToIndex : scrollToIndex)(index, true); | |
} |
I think we don't need any changes in useArrowKeyFocusManager
file.
How about adding state isInitialRender
in SearchRouterList
with default value false and toggle its value in onLayout
of the SelectionList
and pass it to SelectionList
like below.
shouldScrollToFocusedIndex={!isInitialRender}
@nyomanjyotisa I see that the data for different sections is available at different times. I suggest rendering the SelectionList once we fetch all data(sortedRecentSearches, recentReports) from whatever source.
initiallyFocusedOptionKey={styledRecentReports.at(0)?.keyForList}
shouldScrollToFocusedIndex={!isInitialRender} I believe this is more cleaner solution without modifying common component with more states for the initial focus and I think only for the initial render we should focus the item irrespective of textinput entered and gets cleared by the user. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a comment. I also agree with @Pujan92's comments
const isWeb = getPlatform() === CONST.PLATFORM.WEB; | ||
const isDesktop = getPlatform() === CONST.PLATFORM.DESKTOP; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This goes against our best practices - https://github.com/Expensify/App/blob/0dd44ee996d7d2b41ec117205fb52b10a33cf5f0/README.md#platform-specific-file-extensions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Pujan92 should we create platform-specific files for this case?
Seems good, will work on this today |
@Pujan92 have done all your recommendations above, could you check again? Also, should we create platform-specific files for this case? |
@nyomanjyotisa why is the conditional |
The But yeah I think we should use |
@luacmartins I would like to confirm one last thing. I think whenever the search modal opens then only we need to focus first recent item. I have suggested a solution earlier without refocus but asking to clear it out. |
PR and recordings updated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM and tests well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nyomanjyotisa Added cleanup comments as we don't require those changes.
const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false}); | ||
const [autocompleteSuggestions, setAutocompleteSuggestions] = useState<AutocompleteItemData[] | undefined>([]); | ||
const [autocompleteSubstitutions, setAutocompleteSubstitutions] = useState<SubstitutionMap>({}); | ||
|
||
const {isLargeScreenWidth} = useResponsiveLayout(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const {isLargeScreenWidth} = useResponsiveLayout(); |
const setInitialFocus = useCallback(() => { | ||
const initialFocusIndex = (sortedRecentSearches?.slice(0, 5).length ?? 0) + (contextualReportData ? 1 : 0); | ||
listRef.current?.setFocusedIndex(initialFocusIndex); | ||
}, [sortedRecentSearches, contextualReportData]); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const setInitialFocus = useCallback(() => { | |
const initialFocusIndex = (sortedRecentSearches?.slice(0, 5).length ?? 0) + (contextualReportData ? 1 : 0); | |
listRef.current?.setFocusedIndex(initialFocusIndex); | |
}, [sortedRecentSearches, contextualReportData]); |
} else if (!isLargeScreenWidth) { | ||
listRef.current?.updateAndScrollToFocusedIndex(-1); | ||
} else { | ||
setInitialFocus(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} else if (!isLargeScreenWidth) { | |
listRef.current?.updateAndScrollToFocusedIndex(-1); | |
} else { | |
setInitialFocus(); | |
} else { | |
listRef.current?.updateAndScrollToFocusedIndex(-1); | |
} |
useEffect(() => { | ||
if (textInputValue) { | ||
return; | ||
} | ||
setIsInitialRender(true); | ||
}, [textInputValue]); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useEffect(() => { | |
if (textInputValue) { | |
return; | |
} | |
setIsInitialRender(true); | |
}, [textInputValue]); |
@@ -716,12 +721,13 @@ function BaseSelectionList<TItem extends ListItem>( | |||
isTextInputFocusedRef.current = isTextInputFocused; | |||
}, []); | |||
|
|||
useImperativeHandle(ref, () => ({scrollAndHighlightItem, clearInputAfterSelect, updateAndScrollToFocusedIndex, updateExternalTextInputFocus, scrollToIndex}), [ | |||
useImperativeHandle(ref, () => ({scrollAndHighlightItem, clearInputAfterSelect, updateAndScrollToFocusedIndex, updateExternalTextInputFocus, scrollToIndex, setFocusedIndex}), [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
useImperativeHandle(ref, () => ({scrollAndHighlightItem, clearInputAfterSelect, updateAndScrollToFocusedIndex, updateExternalTextInputFocus, scrollToIndex, setFocusedIndex}), [ | |
useImperativeHandle(ref, () => ({scrollAndHighlightItem, clearInputAfterSelect, updateAndScrollToFocusedIndex, updateExternalTextInputFocus, scrollToIndex}), [ |
@nyomanjyotisa Plz resolves the conflicts. I think we don't require below test steps.
|
All looks good, once you merge main and fix conflicts I will approve. |
We just need to resolve conflicts @nyomanjyotisa |
Sorry for the delay, the conflicts resolved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, Thanks @nyomanjyotisa and @luacmartins !!
@@ -310,6 +311,10 @@ function SearchRouter({onRouterClose, shouldHideInputCaret}: SearchRouterProps) | |||
|
|||
const modalWidth = shouldUseNarrowLayout ? styles.w100 : {width: variables.searchRouterPopoverWidth}; | |||
|
|||
const isDataLoaded = useMemo(() => { | |||
return (!contextualReportID || contextualReportID !== undefined) && !isLoadingOnyxValue(recentSearchesMetadata) && recentReports.length > 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NAB: I think we don't need contextualReportID
condition here bcoz currently also that condition truthy for any value.
return (!contextualReportID || contextualReportID !== undefined) && !isLoadingOnyxValue(recentSearchesMetadata) && recentReports.length > 0; | |
return !isLoadingOnyxValue(recentSearchesMetadata) && recentReports.length > 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this a NAB? We should never merge code like this @Pujan92 😒
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It shouldn't be NAB, my bad 😢
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by https://github.com/luacmartins in version: 9.0.69-1 🚀
|
failing with original issue on MWeb Screen_Recording_20241130_184606_Chrome.mp4 |
@nyomanjyotisa @Pujan92 can you have a look into this? |
@mvtglobally these changes are specifically for larger screens as mentioned in the test steps and not for the native/mWeb. |
🚀 Deployed to production by https://github.com/puneetlath in version: 9.0.69-4 🚀
|
Explanation of Change
Fixed Issues
$ #51894
PROPOSAL: #51894 (comment)
Tests
Same as QA Steps
Offline tests
Same as QA Steps
QA Steps
PR Author Checklist
### Fixed Issues
section aboveTests
sectionOffline steps
sectionQA steps
sectiontoggleReport
and notonIconClick
)src/languages/*
files and using the translation methodSTYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)Design
label and/or tagged@Expensify/design
so the design team can review the changes.ScrollView
component to make it scrollable when more elements are added to the page.main
branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTest
steps.Screenshots/Videos
Android: Native
Android-Native.mp4
Android: mWeb Chrome
Android-mWeb.Chrome.mp4
iOS: Native
iOS-Native.mp4
iOS: mWeb Safari
iOS-mWeb.Safari.mp4
MacOS: Chrome / Safari
MacOS-Chrome.mp4
MacOS: Desktop
MacOS-Desktop.mp4